﻿using System;
using System.Windows;
using System.Windows.Controls;
using wi = System.Windows.Interactivity;

namespace Thinktecture.UIAnnotations.Behaviors
{
    public class BehaviorFactory : DependencyObject
    {
        static BehaviorFactory _current;
        
        static BehaviorFactory()
        {
            _current = new BehaviorFactory();
        }

        #region BehaviorTypeName

        public static readonly DependencyProperty BehaviorTypeNameProperty =
            DependencyProperty.RegisterAttached("BehaviorTypeName", typeof(string), typeof(BehaviorFactory),
            new PropertyMetadata("", OnBehaviorTypeNamePropertyChanged));

        [AttachedPropertyBrowsableForType(typeof(Control))]
        public static string GetBehaviorTypeName(UIElement element)
        {
            return (string)element.GetValue(BehaviorTypeNameProperty);
        }

        public static void SetBehaviorTypeName(UIElement element, string value)
        {
            element.SetValue(BehaviorTypeNameProperty, value);
        }

        private static void OnBehaviorTypeNamePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !string.IsNullOrEmpty(e.NewValue.ToString()))
            {
                try
                {
                    var behaviorType = Type.GetType(e.NewValue.ToString());
                    if (behaviorType == null)
                        throw new ArgumentException(string.Format("Can't create behavior type \"{0}\"!", e.NewValue.ToString()));
                    var behavior = Activator.CreateInstance(behaviorType) as wi.Behavior;
                    wi.Interaction.GetBehaviors(sender).Add(behavior);
                }
                catch (Exception ex)
                {
                    throw new ArgumentException(string.Format("Can't create behavior \"{0}\"!", e.NewValue.ToString()), ex);
                }
            }
        }

        #endregion

        #region DetachBehaviorTypeName

        public static readonly DependencyProperty DetachBehaviorTypeNameProperty =
            DependencyProperty.RegisterAttached("DetachBehaviorTypeName", typeof(string), typeof(TargetedTriggerActionFactory),
            new PropertyMetadata("", OnDetachBehaviorTypeNamePropertyChanged));

        [AttachedPropertyBrowsableForType(typeof(Control))]
        public static string GetDetachBehaviorTypeName(UIElement element)
        {
            return (string)element.GetValue(DetachBehaviorTypeNameProperty);
        }

        public static void SetDetachBehaviorTypeName(UIElement element, string value)
        {
            element.SetValue(DetachBehaviorTypeNameProperty, value);
        }

        private static void OnDetachBehaviorTypeNamePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((FrameworkElement)sender).Loaded += _current.OnElementLoaded;
        }

        private void OnElementLoaded(object sender, RoutedEventArgs e)
        {
            var element = sender as FrameworkElement;
            element.Loaded -= _current.OnElementLoaded;
            var typeName = element.GetValue(DetachBehaviorTypeNameProperty) as string;
            if (string.IsNullOrEmpty(typeName))
                return;
            try
            {
                var behaviorType = Type.GetType(typeName);
                if (behaviorType == null)
                    throw new ArgumentException(string.Format("Can't find behavior type \"{0}\"!", typeName));

                var behaviors = wi.Interaction.GetBehaviors(element);
                
                foreach (var b in behaviors)
                {
                    if (b.GetType().Equals(behaviorType))
                    {
                        b.Detach();
                    }
                }
            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("Can't find behavior \"{0}\"!", typeName), ex);
            }
        }

        #endregion

    }
}
